/*************************************************************************

  Operation Wolf C-Chip Protection
  ================================

  The C-Chip (Taito TC0030CMD) is an unidentified mask programmed
  microcontroller of some sort with 64 pins.  It probably has
  about 2k of ROM and 8k of RAM.

  Interesting memory locations shared by cchip/68k:

    14 - dip switch A (written by 68k at start)
    15 - dip switch B (written by 68k at start)
    1b - Current level number (1-6)
    1c - Number of men remaining in level
    1e - Number of helicopters remaining in level
    1f - Number of tanks remaining in level
    20 - Number of boats remaining in level
    21 - Hostages in plane (last level)
    22 - Hostages remaining (last level)/Hostages saved (2nd last level)#
    27 - Set to 1 when final boss is destroyed
    32 - Set to 1 by cchip when level complete (no more enemies remaining)
    34 - Game state (0=attract mode, 1=intro, 2=in-game, 3=end-screen)
    51/52 - Used by cchip to signal change in credit level to 68k
    53 - Credit count
    75 - Set to 1 to trigger end of game boss
    7a - Used to trigger level data select command

  Notes on bootleg c-chip:
    Bootleg cchip forces english language mode
    Bootleg forces round 4 in attract mode
    Bootleg doesn't support service switch
    If you die after round 6 then the bootleg fails to reset the difficulty
    for the next game.

*************************************************************************/

#include "driver.h"

static UINT8 current_bank=0;
static UINT8 current_cmd=0;
static UINT8* cchip_ram=0;
static UINT8 cchip_last_7a=0;
static UINT8 cchip_last_04=0;
static UINT8 cchip_last_05=0;
static UINT8 cchip_coins_for_credit_a=1;
static UINT8 cchip_credit_for_coin_b=2;
static UINT8 cchip_coins=0;
static UINT8 c588=0, c589=0, c58a=0; // These variables derived from the bootleg

static const UINT16 level_data_00[0xcc] =
{
	0x0480,0x1008,0x0300,0x5701,0x0001,0x0010,0x0480,0x1008,
	0x0300,0x5701,0x0001,0x002b,0x0780,0x0009,0x0300,0x4a01,
	0x0004,0x0020,0x0780,0x1208,0x0300,0x5d01,0x0004,0x0030,
	0x0780,0x0209,0x0300,0x4c01,0x0004,0x0038,0x0780,0x0309,
	0x0300,0x4d01,0x0004,0x0048,0x0980,0x1108,0x0300,0x5a01,
	0xc005,0x0018,0x0980,0x0109,0x0300,0x4b01,0xc005,0x0028,
	0x0b80,0x020a,0x0000,0x6401,0x8006,0x0004,0x0c80,0x010b,
	0x0000,0xf201,0x8006,0x8002,0x0b80,0x020a,0x0000,0x6401,
	0x8006,0x0017,0x0c80,0x010b,0x0000,0xf201,0x8006,0x8015,
	0x0b80,0x020a,0x0000,0x6401,0x0007,0x0034,0x0c80,0x010b,
	0x0000,0xf201,0x0007,0x8032,0x0b80,0x020a,0x0000,0x6401,
	0x8006,0x803e,0x0c80,0x010b,0x0000,0xf201,0x8006,0x803d,
	0x0b80,0x100a,0x0000,0x6001,0x0007,0x0008,0x0b80,0x100a,
	0x0000,0x6001,0x0007,0x000b,0x0b80,0x100a,0x0000,0x6001,
	0x0007,0x001b,0x0b80,0x100a,0x0000,0x6001,0x0007,0x001e,
	0x0b80,0x100a,0x0000,0x6001,0x8007,0x0038,0x0b80,0x100a,
	0x0000,0x6001,0x8007,0x003b,0x0b80,0x100a,0x0000,0x6001,
	0x0007,0x8042,0x0b80,0x100a,0x0000,0x6001,0x0007,0x8045,
	0x0c80,0x000b,0x0000,0xf101,0x800b,0x8007,0x0c80,0x000b,
	0x0000,0xf101,0x800b,0x801a,0x0c80,0x000b,0x0000,0xf101,
	0x000c,0x8037,0x0c80,0x000b,0x0000,0xf101,0x800b,0x0042,
	0x0c80,0xd04b,0x0000,0xf301,0x8006,0x8009,0x0c80,0xd04b,
	0x0000,0xf301,0x8006,0x801c,0x0c80,0xd04b,0x0000,0xf301,
	0x8006,0x0044,0x0c80,0x030b,0x0000,0xf401,0x0008,0x0028,
	0x0c80,0x030b,0x0000,0xf401,0x0008,0x804b,0x0c00,0x040b,
	0x0000,0xf501,0x0008,0x8026
};

static const UINT16 level_data_01[0xcc] =
{
	0x0780,0x0209,0x0300,0x4c01,0x0004,0x0010,0x0780,0x0209,
	0x0300,0x4c01,0x4004,0x0020,0x0780,0x0309,0x0300,0x4d01,
	0xe003,0x0030,0x0780,0x0309,0x0300,0x4d01,0x8003,0x0040,
	0x0780,0x0209,0x0300,0x4c01,0x8004,0x0018,0x0780,0x0309,
	0x0300,0x4d01,0xc003,0x0028,0x0b80,0x000b,0x0000,0x0b02,
	0x8009,0x0029,0x0b80,0x0409,0x0000,0x0f02,0x8008,0x8028,
	0x0b80,0x040a,0x0000,0x3502,0x000a,0x8028,0x0b80,0x050a,
	0x0000,0x1002,0x8006,0x8028,0x0b80,0x120a,0x0000,0x3602,
	0x0008,0x004d,0x0b80,0x120a,0x0000,0x3602,0x0008,0x004f,
	0x0b80,0x120a,0x0000,0x3602,0x0008,0x0001,0x0b80,0x120a,
	0x0000,0x3602,0x0008,0x0003,0x0b80,0x130a,0x0000,0x3a02,
	0x0007,0x0023,0x0b80,0x130a,0x0000,0x3a02,0x0007,0x8025,
	0x0b80,0x130a,0x0000,0x3a02,0x8009,0x0023,0x0b80,0x130a,
	0x0000,0x3a02,0x8009,0x8025,0x0b80,0x140a,0x0000,0x3e02,
	0x0007,0x000d,0x0b80,0x140a,0x0000,0x3e02,0x0007,0x800f,
	0x0b80,0x000b,0x0000,0x0102,0x0007,0x804e,0x0b80,0xd24b,
	0x0000,0x0302,0x0007,0x000e,0x0b80,0x000b,0x0000,0x0402,
	0x8006,0x0020,0x0b80,0xd34b,0x0000,0x0502,0x8006,0x0024,
	0x0b80,0x000b,0x0000,0x0602,0x8009,0x0001,0x0b80,0xd44b,
	0x0000,0x0702,0x800b,0x800b,0x0b80,0xd54b,0x0000,0x0802,
	0x800b,0x000e,0x0b80,0x000b,0x0000,0x0902,0x800b,0x0010,
	0x0b80,0x000b,0x0000,0x0a02,0x0009,0x0024,0x0b80,0xd64b,
	0x0000,0x0c02,0x000c,0x8021,0x0b80,0x000b,0x0000,0x0d02,
	0x000c,0x0025,0x0b80,0x000b,0x0000,0x0e02,0x8009,0x004e,
	0x0b80,0x0609,0x0300,0x4e01,0x8006,0x8012,0x0b80,0x0609,
	0x0300,0x4e01,0x0007,0x8007
};

static const UINT16 level_data_02[0xcc] =
{
	0x0480,0x000b,0x0300,0x4501,0x0001,0x0018,0x0480,0x000b,
	0x0300,0x4501,0x2001,0x0030,0x0780,0x1208,0x0300,0x5d01,
	0x0004,0x0010,0x0780,0x1208,0x0300,0x5d01,0x2004,0x001c,
	0x0780,0x1208,0x0300,0x5d01,0xe003,0x0026,0x0780,0x1208,
	0x0300,0x5d01,0x8003,0x0034,0x0780,0x1208,0x0300,0x5d01,
	0x3004,0x0040,0x0780,0x010c,0x0300,0x4601,0x4004,0x0022,
	0x0780,0x010c,0x0300,0x4601,0x6004,0x0042,0x0780,0x000c,
	0x0500,0x7b01,0x800b,0x0008,0x0780,0x010c,0x0300,0x4601,
	0x2004,0x0008,0x0000,0x0000,0x0000,0xf001,0x0000,0x0000,
	0x0000,0x0000,0x0000,0xf001,0x0000,0x0000,0x0000,0x0000,
	0x0000,0xf001,0x0000,0x0000,0x0b80,0x000b,0x0000,0x1902,
	0x000b,0x0004,0x0b80,0x000b,0x0000,0x1a02,0x0009,0x8003,
	0x0b80,0x000b,0x0000,0x1902,0x000b,0x000c,0x0b80,0x000b,
	0x0000,0x1a02,0x0009,0x800b,0x0b80,0x000b,0x0000,0x1902,
	0x000b,0x001c,0x0b80,0x000b,0x0000,0x1a02,0x0009,0x801b,
	0x0b80,0x000b,0x0000,0x1902,0x000b,0x002c,0x0b80,0x000b,
	0x0000,0x1a02,0x0009,0x802b,0x0b80,0x000b,0x0000,0x1902,
	0x000b,0x0044,0x0b80,0x000b,0x0000,0x1a02,0x0009,0x8043,
	0x0b80,0x000b,0x0000,0x1902,0x000b,0x004c,0x0b80,0x000b,
	0x0000,0x1a02,0x0009,0x804b,0x0b80,0x020c,0x0300,0x4801,
	0xa009,0x0010,0x0b80,0x020c,0x0300,0x4801,0xa009,0x0028,
	0x0b80,0x020c,0x0300,0x4801,0xa009,0x0036,0x0000,0x0000,
	0x0000,0xf001,0x0000,0x0000,0x0000,0x0000,0x0000,0xf001,
	0x0000,0x0000,0x0000,0x0000,0x0000,0xf001,0x0000,0x0000,
	0x0000,0x0000,0x0000,0xf001,0x0000,0x0000,0x0000,0x0000,
	0x0000,0xf001,0x0000,0x0000
};

static const UINT16 level_data_03[0xcc] =
{
	0x0480,0x000b,0x0300,0x4501,0x0001,0x0018,0x0480,0x000b,
	0x0300,0x4501,0x2001,0x002b,0x0780,0x010c,0x0300,0x4601,
	0x0004,0x000d,0x0780,0x000c,0x0500,0x7b01,0x800b,0x0020,
	0x0780,0x010c,0x0300,0x4601,0x2004,0x0020,0x0780,0x010c,
	0x0300,0x4601,0x8003,0x0033,0x0780,0x010c,0x0300,0x4601,
	0x0004,0x003c,0x0780,0x010c,0x0300,0x4601,0xd003,0x0045,
	0x0780,0x000c,0x0500,0x7b01,0x900b,0x0041,0x0780,0x010c,
	0x0300,0x4601,0x3004,0x0041,0x0b80,0x020c,0x0300,0x4801,
	0x0007,0x0000,0x0b80,0x410a,0x0000,0x2b02,0xe006,0x4049,
	0x0b80,0x020c,0x0300,0x4801,0x8007,0x000b,0x0b80,0x000b,
	0x0000,0x2702,0x800a,0x8005,0x0b80,0x000b,0x0000,0x1e02,
	0x0008,0x800e,0x0b80,0x000b,0x0000,0x1f02,0x8007,0x0011,
	0x0b80,0x000b,0x0000,0x2802,0x000b,0x0012,0x0b80,0x000b,
	0x0000,0x2002,0x0007,0x8015,0x0b80,0x000b,0x0000,0x2102,
	0x0007,0x801b,0x0b80,0x000b,0x0000,0x2902,0x800a,0x001a,
	0x0b80,0x000b,0x0000,0x2202,0x8007,0x001e,0x0b80,0x000b,
	0x0000,0x1e02,0x0008,0x0025,0x0b80,0x000b,0x0000,0x2302,
	0x8007,0x802c,0x0b80,0x000b,0x0000,0x2802,0x000b,0x8028,
	0x0b80,0x020c,0x0300,0x4801,0x0007,0x0030,0x0b80,0x400a,
	0x0000,0x2e02,0x4007,0x002d,0x0b80,0x000b,0x0000,0x2702,
	0x800a,0x8035,0x0b80,0x020c,0x0300,0x4801,0x8007,0x0022,
	0x0b80,0x000b,0x0000,0x2402,0x8007,0x0047,0x0b80,0x000b,
	0x0000,0x2a02,0x800a,0x004b,0x0b80,0x000b,0x0000,0x2502,
	0x0007,0x804b,0x0b80,0x000b,0x0000,0x2602,0x0007,0x004e,
	0x0b80,0x020c,0x0300,0x4801,0x0007,0x8043,0x0b80,0x020c,
	0x0300,0x4801,0x8007,0x803d
};

static const UINT16 level_data_04[0xcc] =
{
	0x0780,0x0209,0x0300,0x4c01,0x0004,0x0010,0x0780,0x0209,
	0x0300,0x4c01,0x4004,0x0020,0x0780,0x0309,0x0300,0x4d01,
	0xe003,0x0030,0x0780,0x0309,0x0300,0x4d01,0x8003,0x0040,
	0x0780,0x0209,0x0300,0x4c01,0x8004,0x0018,0x0780,0x0309,
	0x0300,0x4d01,0xc003,0x0028,0x0780,0x000b,0x0300,0x5601,
	0x8004,0x0008,0x0780,0x000b,0x0300,0x5601,0x8004,0x0038,
	0x0780,0x000b,0x0300,0x5501,0x8004,0x0048,0x0980,0x0509,
	0x0f00,0x0f01,0x4005,0x4007,0x0980,0x0509,0x0f00,0x0f01,
	0x4005,0x4037,0x0b80,0x030a,0x0000,0x1302,0x8006,0x0040,
	0x0b80,0x110a,0x0000,0x1502,0x8008,0x8048,0x0b80,0x110a,
	0x0000,0x1502,0x8008,0x8049,0x0b80,0x000b,0x0000,0xf601,
	0x0007,0x8003,0x0b80,0x000b,0x0000,0xf701,0x0007,0x0005,
	0x0b80,0x000b,0x0000,0xf901,0x0007,0x8008,0x0b80,0x000b,
	0x0000,0xf901,0x0007,0x0010,0x0b80,0x000b,0x0000,0xfa01,
	0x0007,0x8013,0x0b80,0x000b,0x0000,0xf801,0x800b,0x800b,
	0x0b80,0x000b,0x0000,0x0002,0x800b,0x801a,0x0b80,0x000b,
	0x0000,0xf901,0x0007,0x8017,0x0b80,0x000b,0x0000,0xfa01,
	0x0007,0x001b,0x0b80,0x000b,0x0000,0xf801,0x800b,0x0013,
	0x0b80,0x000b,0x0000,0x4202,0x800b,0x0016,0x0b80,0x000b,
	0x0000,0xfb01,0x8007,0x8020,0x0b80,0x000b,0x0000,0xf601,
	0x0007,0x8023,0x0b80,0x000b,0x0000,0x4202,0x800b,0x800e,
	0x0b80,0x000b,0x0000,0x4302,0x800b,0x801d,0x0b80,0x000b,
	0x0000,0xf701,0x0007,0x0025,0x0b80,0x000b,0x0000,0xfd01,
	0x8006,0x003f,0x0b80,0x000b,0x0000,0xfe01,0x0007,0x0046,
	0x0b80,0x000b,0x0000,0xff01,0x8007,0x8049,0x0b80,0x000b,
	0x0000,0xfc01,0x8009,0x0042
};

const UINT16 level_data_05[0xcc] =
{
	0x0480,0x1008,0x0300,0x5701,0x0001,0x0010,0x0480,0x1008,
	0x0300,0x5701,0x0001,0x002b,0x0780,0x0009,0x0300,0x4a01,
	0x0004,0x0020,0x0780,0x1208,0x0300,0x5d01,0x0004,0x0030,
	0x0780,0x0209,0x0300,0x4c01,0x0004,0x0038,0x0780,0x0309,
	0x0300,0x4d01,0x0004,0x0048,0x0980,0x1108,0x0300,0x5a01,
	0xc005,0x0018,0x0980,0x0109,0x0300,0x4b01,0xc005,0x0028,
	0x0b80,0x020a,0x0000,0x6401,0x8006,0x0004,0x0c80,0x010b,
	0x0000,0xf201,0x8006,0x8002,0x0b80,0x020a,0x0000,0x6401,
	0x8006,0x0017,0x0c80,0x010b,0x0000,0xf201,0x8006,0x8015,
	0x0b80,0x020a,0x0000,0x6401,0x0007,0x0034,0x0c80,0x010b,
	0x0000,0xf201,0x0007,0x8032,0x0b80,0x020a,0x0000,0x6401,
	0x8006,0x803e,0x0c80,0x010b,0x0000,0xf201,0x8006,0x803d,
	0x0b80,0x100a,0x0000,0x6001,0x0007,0x0008,0x0b80,0x100a,
	0x0000,0x6001,0x0007,0x000b,0x0b80,0x100a,0x0000,0x6001,
	0x0007,0x001b,0x0b80,0x100a,0x0000,0x6001,0x0007,0x001e,
	0x0b80,0x100a,0x0000,0x6001,0x8007,0x0038,0x0b80,0x100a,
	0x0000,0x6001,0x8007,0x003b,0x0b80,0x100a,0x0000,0x6001,
	0x0007,0x8042,0x0b80,0x100a,0x0000,0x6001,0x0007,0x8045,
	0x0c80,0x000b,0x0000,0xf101,0x800b,0x8007,0x0c80,0x000b,
	0x0000,0xf101,0x800b,0x801a,0x0c80,0x000b,0x0000,0xf101,
	0x000c,0x8037,0x0c80,0x000b,0x0000,0xf101,0x800b,0x0042,
	0x0c80,0xd04b,0x0000,0xf301,0x8006,0x8009,0x0c80,0xd04b,
	0x0000,0xf301,0x8006,0x801c,0x0c80,0xd04b,0x0000,0xf301,
	0x8006,0x0044,0x0c80,0x030b,0x0000,0xf401,0x0008,0x0028,
	0x0c80,0x030b,0x0000,0xf401,0x0008,0x804b,0x0c00,0x040b,
	0x0000,0xf501,0x0008,0x8026
};

static const UINT16 level_data_06[0xcc] =
{
	0x0000,0x1008,0x0300,0x5701,0x0001,0x0010,0x0000,0x1008,
	0x0300,0x5701,0x0001,0x002b,0x0000,0x0000,0x0000,0x0000,
	0x0000,0x0000,0x0700,0x0009,0x0300,0x4a01,0x0004,0x0020,
	0x0700,0x1208,0x0300,0x5d01,0x0004,0x0030,0x0700,0x0209,
	0x0300,0x4c01,0x0004,0x0038,0x0700,0x0309,0x0300,0x4d01,
	0x0004,0x0048,0x0900,0x1108,0x0300,0x5a01,0xc005,0x0018,
	0x0900,0x0109,0x0300,0x4b01,0xc005,0x0028,0x0000,0x000b,
	0x0000,0x0000,0x0018,0x0000,0x0000,0x000b,0x0000,0x0000,
	0x0018,0x0000,0x0000,0x000b,0x0000,0x0000,0x0018,0x0000,
	0x0000,0x000b,0x0000,0x0000,0x0018,0x0000,0x0000,0x000b,
	0x0000,0x0000,0x0018,0x0000,0x0000,0x000b,0x0000,0x0000,
	0x0018,0x0000,0x0000,0x000b,0x0000,0x0000,0x0018,0x0000,
	0x0000,0x000b,0x0000,0x0000,0x0018,0x0000,0x0000,0x000b,
	0x0000,0x0000,0x0018,0x0000,0x0980,0xdb4c,0x0000,0x3202,
	0x0006,0x0004,0x0b80,0x0609,0x0300,0x4e01,0x5006,0x8002,
	0x0b80,0x0609,0x0300,0x4e01,0x5006,0x8003,0x0b80,0x0609,
	0x0300,0x4e01,0x5006,0x8004,0x0b80,0x0609,0x0300,0x4e01,
	0x5006,0x0008,0x0b80,0x0609,0x0300,0x4e01,0x5006,0x0010,
	0x0b80,0x0609,0x0300,0x4e01,0x5006,0x0012,0x0b80,0x0609,
	0x0300,0x4e01,0x5006,0x0014,0x0b80,0x0609,0x0300,0x4e01,
	0x5006,0x0016,0x0b80,0x0609,0x0300,0x4e01,0x5006,0x0018,
	0x0b80,0x0609,0x0300,0x4e01,0x5006,0x0020,0x0b80,0x0609,
	0x0300,0x4e01,0x5006,0x0023,0x0b80,0x0609,0x0300,0x4e01,
	0x5006,0x0030,0x0b80,0x0609,0x0300,0x4e01,0x5006,0x0038,
	0x0b80,0x0609,0x0300,0x4e01,0x5006,0x0040,0x0b80,0x0609,
	0x0300,0x4e01,0x5006,0x0042
};

static const UINT16* level_data_lookup[] =
{
	level_data_00,
	level_data_01,
	level_data_02,
	level_data_03,
	level_data_04,
	level_data_05,
	level_data_06,
};


static void timer_callback(int param)
{
	// Level data command
	if (current_cmd==0xf5)
	{
		int level=cchip_ram[0x1b];
		const UINT16* level_data=level_data_lookup[level];
		int i=0;
		for (i=0; i<0xcc; i++)
		{
			cchip_ram[0x200 + i*2 + 0]=level_data[i]>>8;
			cchip_ram[0x200 + i*2 + 1]=level_data[i]&0xff;
		}

		// The bootleg cchip writes 0 to these locations - hard to tell what the real one writes
		cchip_ram[0x0]=0;
		cchip_ram[0x76]=0;
		cchip_ram[0x75]=0;
		cchip_ram[0x74]=0;
		cchip_ram[0x72]=0;
		cchip_ram[0x71]=0;
		cchip_ram[0x70]=0;
		cchip_ram[0x66]=0;
		cchip_ram[0x2b]=0;
		cchip_ram[0x30]=0;
		cchip_ram[0x31]=0;
		cchip_ram[0x32]=0;
		cchip_ram[0x27]=0;
		c588=0;
		c589=0;
		c58a=0;

		cchip_ram[0x1a]=0;
		cchip_ram[0x7a]=1; // Signal command complete
	}

	current_cmd=0;
}

static void updateDifficulty(int mode)
{
	// The game is made up of 6 rounds, when you complete the
	// sixth you return to the start but with harder difficulty.
	if (mode==0)
	{
		switch (cchip_ram[0x15]&3) // Dipswitch B
		{
		case 3:
			cchip_ram[0x2c]=0x31;
			cchip_ram[0x77]=0x05;
			cchip_ram[0x25]=0x0f;
			cchip_ram[0x26]=0x0b;
			break;
		case 0:
			cchip_ram[0x2c]=0x20;
			cchip_ram[0x77]=0x06;
			cchip_ram[0x25]=0x07;
			cchip_ram[0x26]=0x03;
			break;
		case 1:
			cchip_ram[0x2c]=0x31;
			cchip_ram[0x77]=0x05;
			cchip_ram[0x25]=0x0f;
			cchip_ram[0x26]=0x0b;
			break;
		case 2:
			cchip_ram[0x2c]=0x3c;
			cchip_ram[0x77]=0x04;
			cchip_ram[0x25]=0x13;
			cchip_ram[0x26]=0x0f;
			break;
		}
	}
	else
	{
		switch (cchip_ram[0x15]&3) // Dipswitch B
		{
		case 3:
			cchip_ram[0x2c]=0x46;
			cchip_ram[0x77]=0x5;
			cchip_ram[0x25]=0x11;
			cchip_ram[0x26]=0xe;
			break;
		case 0:
			cchip_ram[0x2c]=0x30;
			cchip_ram[0x77]=0x6;
			cchip_ram[0x25]=0xb;
			cchip_ram[0x26]=0x3;
			break;
		case 1:
			cchip_ram[0x2c]=0x3a;
			cchip_ram[0x77]=0x5;
			cchip_ram[0x25]=0xf;
			cchip_ram[0x26]=0x9;
			break;
		case 2:
			cchip_ram[0x2c]=0x4c;
			cchip_ram[0x77]=0x4;
			cchip_ram[0x25]=0x19;
			cchip_ram[0x26]=0x11;
			break;
		};
	}
}

/*************************************
 *
 * Writes to C-Chip - Important Bits
 *
 *************************************/

WRITE16_HANDLER( opwolf_cchip_status_w )
{
	// This is written once after the C-Chip init is complete (and passes)
	// We use it to setup some initial state (it's not clear if the real
	// c-chip sets this here, or if it's as a side-effect of the other
	// init sequence data).

	cchip_ram[0x3d]=1;
	cchip_ram[0x7a]=1;
	updateDifficulty(0);
}

WRITE16_HANDLER( opwolf_cchip_bank_w )
{
	current_bank=data&7;
}

WRITE16_HANDLER( opwolf_cchip_data_w )
{
	cchip_ram[(current_bank * 0x400) + offset]=data&0xff;

//  if (offset!=0x64 && offset!=0x65 && offset!=0x66 && offset!=0x67 && offset!=0x68 && offset!=0x69)
//      logerror("%08x:  opwolf c write %04x %04x\n", activecpu_get_pc(), offset,data);

	if (current_bank == 0)
	{
		// Dip switch A is written here by the 68k - precalculate the coinage values
		if (offset == 0x14)
		{
			switch (data&0x30)
			{
			case 0x00: cchip_coins_for_credit_a=4; break;
			case 0x10: cchip_coins_for_credit_a=3; break;
			case 0x20: cchip_coins_for_credit_a=2; break;
			case 0x30: cchip_coins_for_credit_a=1; break;
			}

			switch (data&0xc0)
			{
			case 0x00: cchip_credit_for_coin_b=6; break;
			case 0x40: cchip_credit_for_coin_b=4; break;
			case 0x80: cchip_credit_for_coin_b=3; break;
			case 0xc0: cchip_credit_for_coin_b=2; break;
			}
		}

		// Dip switch B
		if (offset == 0x15)
		{
			updateDifficulty(0);
		}
	}
}


/*************************************
 *
 * Reads from C-Chip
 *
 *************************************/

READ16_HANDLER( opwolf_cchip_status_r )
{
	/*
        Bit 0x4 = Error signal
        Bit 0x1 = Ready signal
    */
	return 0x1; /* Return 0x5 for C-Chip error */
}

READ16_HANDLER( opwolf_cchip_data_r )
{
//  if (offset!=0x7f && offset!=0x1c && offset!=0x1d && offset!=0x1e && offset!=0x1f && offset!=0x20 && activecpu_get_pc()!=0xc18 && activecpu_get_pc()!=0xc2e && activecpu_get_pc()!=0xc9e && offset!=0x50 && offset!=0x51 && offset!=0x52 && offset!=0x53 && offset!=0x5 && offset!=0x13 && offset!=0x79 && offset!=0x12 && offset!=0x34)
//      logerror("%08x:  opwolf c read %04x (bank %04x)\n", activecpu_get_pc(), offset, current_bank);

	return cchip_ram[(current_bank * 0x400) + offset];
}

/*************************************
 *
 * C-Chip Tick
 *
 *************************************/

static void cchip_timer(int dummy)
{
	// Update input ports, these are used by both the 68k directly and by the c-chip
	cchip_ram[0x4]=input_port_0_word_r(0,0);
	cchip_ram[0x5]=input_port_1_word_r(0,0);

	// Update coins - cchip handles coinage according to dipswitch A
	if (cchip_ram[0x4]!=cchip_last_04)
	{
		// Coin slot A
		if (cchip_ram[0x4]&1)
		{
			cchip_coins++;
			if (cchip_coins >= cchip_coins_for_credit_a)
			{
				cchip_ram[0x53]++;
				cchip_ram[0x51]=0x55;
				cchip_ram[0x52]=0x55;
				cchip_coins=0;
			}
			coin_counter_w(0, 1);
		}

		// Coin slot B
		if (cchip_ram[0x4]&2)
		{
			cchip_ram[0x53]+=cchip_credit_for_coin_b;
			cchip_ram[0x51]=0x55;
			cchip_ram[0x52]=0x55;
			coin_counter_w(1, 1);
		}

		if (cchip_ram[0x53]>9)
			cchip_ram[0x53]=9;
	}
	cchip_last_04=cchip_ram[0x4];

	// Service switch
	if (cchip_ram[0x5]!=cchip_last_05)
	{
		if ((cchip_ram[0x5]&4)==0)
		{
			cchip_ram[0x53]++;
			cchip_ram[0x51]=0x55;
			cchip_ram[0x52]=0x55;
		}
	}
	cchip_last_05=cchip_ram[0x5];

	// Cchip handles coin lockout (68k flags error if more than 9 coins)
	coin_lockout_w(1, cchip_ram[0x53]==9);
	coin_lockout_w(0, cchip_ram[0x53]==9);
	coin_counter_w(0, 0);
	coin_counter_w(1, 0);

	// Special handling for last level
	if (cchip_ram[0x1b]==0x6)
	{
		// Check for triggering final helicopter (end boss)
		if (c58a==0)
		{
			if ((cchip_ram[0x72]&0x7f) >= 8 && cchip_ram[0x74]==0 && cchip_ram[0x1c]==0 && cchip_ram[0x1d]==0 && cchip_ram[0x1f]==0)
			{
				cchip_ram[0x30]=1;
				cchip_ram[0x74]=1;
				c58a=1;
			}
		}

		if (cchip_ram[0x1a]==0x90)
			cchip_ram[0x74]=0;

		if (c58a!=0)
		{
			if (c589==0 && cchip_ram[0x27]==0 && cchip_ram[0x75]==0 && cchip_ram[0x1c]==0 && cchip_ram[0x1d]==0 && cchip_ram[0x1e]==0 && cchip_ram[0x1f]==0)
			{
				cchip_ram[0x31]=1;
				cchip_ram[0x75]=1;
				c589=1;
			}
		}

		if (cchip_ram[0x2b]==0x1)
		{
			cchip_ram[0x2b]=0;

			if (cchip_ram[0x30]==0x1)
			{
				if (cchip_ram[0x1a]!=0x90)
					cchip_ram[0x1a]--;
			}

			if (cchip_ram[0x72]==0x9)
			{
				if (cchip_ram[0x76]!=0x4)
				{
					cchip_ram[0x76]=3;
				}
			}
			else
			{
				// This timer is derived from the bootleg rather than the real board, I'm not 100% sure about it
				c588|=0x80;

				cchip_ram[0x72]=c588;
				c588++;

				cchip_ram[0x1a]--;
				cchip_ram[0x1a]--;
				cchip_ram[0x1a]--;
			}
		}

		// Update difficulty settings
		if (cchip_ram[0x76]==0)
		{
			cchip_ram[0x76]=1;
			updateDifficulty(1);
		}
	}

	// These variables are cleared every frame during attract mode and the intro.
	if (cchip_ram[0x34] < 2)
	{
		updateDifficulty(0);
		cchip_ram[0x76]=0;
		cchip_ram[0x75]=0;
		cchip_ram[0x74]=0;
		cchip_ram[0x72]=0;
		cchip_ram[0x71]=0;
		cchip_ram[0x70]=0;
		cchip_ram[0x66]=0;
		cchip_ram[0x2b]=0;
		cchip_ram[0x30]=0;
		cchip_ram[0x31]=0;
		cchip_ram[0x32]=0;
		cchip_ram[0x27]=0;
		c588=0;
		c589=0;
		c58a=0;
	}

	// Check for level completion (all enemies destroyed)
	if (cchip_ram[0x1c] == 0 && cchip_ram[0x1d] == 0 && cchip_ram[0x1e] == 0 && cchip_ram[0x1f] == 0 && cchip_ram[0x20] == 0)
	{
		// Special handling for end of level 6
		if (cchip_ram[0x1b]==0x6)
		{
			// Don't signal end of level until final boss is destroyed
			if (cchip_ram[0x27]==0x1)
				cchip_ram[0x32]=1;
		}
		else
		{
			// Signal end of level
			cchip_ram[0x32]=1;
		}
	}

	if (cchip_ram[0xe] == 1)
	{
		cchip_ram[0xe]=0xfd;
		cchip_ram[0x61]=0x04;
	}

	// Access level data command (address 0xf5 goes from 1 -> 0)
	if (cchip_ram[0x7a]==0 && cchip_last_7a!=0 && current_cmd!=0xf5)
	{
		// Simulate time for command to execute (exact timing unknown, this is close)
		current_cmd=0xf5;
		timer_set(TIME_IN_CYCLES(80000,0), 0, timer_callback);
	}
	cchip_last_7a=cchip_ram[0x7a];

	// This seems to some kind of periodic counter - results are expected
	// by the 68k when the counter reaches 0xa
	if (cchip_ram[0x7f]==0xa)
	{
		cchip_ram[0xfe]=0xf7;
		cchip_ram[0xff]=0x6e;
	}

	// These are set every frame
	cchip_ram[0x64]=0;
	cchip_ram[0x66]=0;
}

/*************************************
 *
 * C-Chip State Saving
 *
 *************************************/

void opwolf_cchip_init(void)
{
	cchip_ram=auto_malloc(0x400 * 8);

	state_save_register_global(current_bank);
	state_save_register_global(current_cmd);
	state_save_register_global(cchip_last_7a);
	state_save_register_global(cchip_last_04);
	state_save_register_global(cchip_last_05);
	state_save_register_global(c588);
	state_save_register_global(c589);
	state_save_register_global(c58a);
	state_save_register_global(cchip_coins);
	state_save_register_global(cchip_coins_for_credit_a);
	state_save_register_global(cchip_credit_for_coin_b);
	state_save_register_global_pointer(cchip_ram, 0x400 * 8);

	cchip_last_7a=0;
	cchip_last_04=0xfc;
	cchip_last_05=0xff;
	cchip_coins=0;
	cchip_coins_for_credit_a=1;
	cchip_credit_for_coin_b=2;

	timer_pulse(TIME_IN_HZ(60), 0, cchip_timer);
}
